package util;

import java.text.DecimalFormat;
import java.util.Date;

public class Candle {
	
	private String stockName;
	private Date date;
	private int volume;
	private int valueRank;
	private int volumeRank;
	private float priceHigh;
	private float priceLow;
	private float priceOpened;
	private float priceClosed;
	private float tickSize;

	public Date getDate() {
		return date;
	}
	
	public int getVolume() {
		return volume;
	}
	
	public float getPriceLow() {
		return priceLow;
	}
	
	public float getPriceOpened() {
		return priceOpened;
	}
	
	public float getPriceClosed() {
		return priceClosed;
	}
	
		public String getStockName() {
		return stockName;
	}
	
	public Candle(String name, Date date, int volume, float priceHigh, float priceLow, float priceOpened, float priceClosed) {
		this.stockName = name;
		this.date = date;
		this.volume = volume;
		this.priceHigh = priceHigh;
		this.priceLow = priceLow;
		this.priceOpened = priceOpened;
		this.priceClosed = priceClosed;
		
		tickSize = 0.01f;
		if (priceClosed < 2) tickSize = 0.005f;
		if (priceClosed < 0.2) tickSize = 0.001f;
	}
	
	public float getHammerRatio(Candle candleYtd) {
		if (priceHigh == 0) return 0;
		if (priceLow == 0) return 0;
		if (priceOpened == 0) return 0;
		if (priceClosed == 0) return 0;
		
		float bodyLength = priceClosed - priceOpened;
		if (isBlack()) return 0;
		if (isDoji()) bodyLength = tickSize;
		if (candleYtd.priceLow < priceLow) return 0;

		float tailJoint = Math.min(priceOpened, priceClosed);
		float tailLength = tailJoint - priceLow;
		
		float ratio = tailLength / bodyLength;
		
		return ratio;
	}

	public float getEngulfingRatio(Candle candleToday) {
		if (priceHigh == 0) return -1;
		if (priceLow == 0) return -1;
		if (priceOpened == 0) return -1;
		if (priceClosed == 0) return -1;
		
		if (!isBlack()) return -1;
		if (!candleToday.isWhite()) return -1;
		
		//if (priceOpened > candleToday.priceClosed) return -1;
		//if (priceClosed < candleToday.priceOpened) return -1;

		float bodyLengthYtd = priceOpened - priceClosed;
		float bodyLengthToday = candleToday.priceClosed - candleToday.priceOpened;
		
		float ratio = bodyLengthToday / bodyLengthYtd;
		if (ratio > 10) return -1;
		return ratio;
	}

	public float getHaramiRatio(Candle candleToday) {
		if (priceHigh == 0) return -1;
		if (priceLow == 0) return -1;
		if (priceOpened == 0) return -1;
		if (priceClosed == 0) return -1;
		
		if (!isBlack()) return -1;
		if (!candleToday.isWhite()) return -1;
		
		//if (candleToday.priceClosed > priceOpened) return -1;
		//if (candleToday.priceOpened < priceClosed) return -1;

		float bodyLengthYtd = priceOpened - priceClosed;
		float bodyLengthToday = candleToday.priceClosed - candleToday.priceOpened;
		
		float ratio = bodyLengthYtd / bodyLengthToday;
		if (ratio > 10) return -1;
		return ratio;
	}

	public float getPiercingRatio(int minTicks, Candle candleToday) {
		if (priceHigh == 0) return -1;
		if (priceLow == 0) return -1;
		if (priceOpened == 0) return -1;
		if (priceClosed == 0) return -1;
		
		if (!isBlack()) return -1;
		if (!candleToday.isWhite()) return -1;
		
		float bodyLengthYtd = priceOpened - priceClosed;
		float bodyLengthToday = candleToday.priceClosed - candleToday.priceOpened;
		
		if (candleToday.priceClosed < (priceClosed + priceOpened) / 2) return -1;

		float minBodyLength = Math.min(bodyLengthYtd, bodyLengthToday);
		if (minBodyLength / tickSize < minTicks) return -1; 
			
		float ratio = bodyLengthToday / bodyLengthYtd;
		if (ratio < 0.7) return -1;
		if (ratio > 2) return -1;
		return ratio;
	}
	
	public boolean isPriceLowReversed(Candle candle_1, Candle candle_0) {
		if (!hasBody()) return false;
		if (!candle_1.hasBody()) return false;
		if (!candle_0.hasBody()) return false;
		
		float p_2 = getPriceLow();
		float p_1 = candle_1.getPriceLow();
		float p_0 = candle_0.getPriceLow();
		
		if (p_0 > p_1 && p_2 > p_1) {
			return true;
		}
		else return false;
	}
	
	public float getWilliamsR(Candle candle_1, Candle candle_0) {
		if (priceHigh == 0) return -1;
		if (priceLow == 0) return -1;
		if (priceOpened == 0) return -1;
		if (priceClosed == 0) return -1;
		if (priceClosed == priceHigh) return -1;

		if (candle_1.priceHigh == 0) return -1;
		if (candle_1.priceLow == 0) return -1;
		if (candle_1.priceOpened == 0) return -1;
		if (candle_1.priceClosed == 0) return -1;
		if (candle_1.priceClosed == candle_1.priceHigh) return -1;
		
		if (candle_0.priceHigh == 0) return -1;
		if (candle_0.priceLow == 0) return -1;
		if (candle_0.priceOpened == 0) return -1;
		if (candle_0.priceClosed == 0) return -1;
		if (candle_0.priceClosed == candle_0.priceHigh) return -1;
		
		float high = Math.max(priceHigh, Math.max(candle_1.priceHigh, candle_0.priceHigh));
		float low = Math.min(priceLow, Math.min(candle_1.priceLow, candle_0.priceLow));
		float r = (high - candle_0.priceClosed) / (high - low);
		return r;
	}
	
	public boolean is2White(Candle candle_1, Candle candle_0) {
		if (!candle_0.hasMoreVolumeThan(candle_1)) return false;
		if (!candle_1.hasMoreVolumeThan(this)) return false;

		if (candle_0.isWhite() && candle_1.isWhite() && candle_0.closesHigherThan(candle_1)) {
			return true;
		}
		return false;
	}
	
	public int isSupported(int maxTicks, Candle candle_1, Candle candle_0) {
		if (priceHigh == 0) return -1;
		if (priceLow == 0) return -1;
		if (priceOpened == 0) return -1;
		if (priceClosed == 0) return -1;

		if (!hasTail() && !candle_1.hasTail() && !candle_0.hasTail()) return -1;
		if (isDash() || candle_1.isDash() && candle_0.isDash()) return -1;
		
		float lowestLow = Math.min(priceLow, Math.min(candle_1.priceLow, candle_0.priceLow));
		float highestLow = Math.max(priceLow, Math.max(candle_1.priceLow, candle_0.priceLow));
		float diff = highestLow - lowestLow;
		double d = diff * 1000;
		d = Math.round(d);
		d = d/1000;
		double ticks = d / tickSize;
		if (ticks <= maxTicks) {
			int numTicks = getTailLengthInTicks();
			numTicks += candle_1.getTailLengthInTicks();
			numTicks += candle_0.getTailLengthInTicks();
			return numTicks;
		}
		return -1;
	}
	
	public boolean closesHigherThan(Candle candle_1) {
		if (priceClosed == 0) return false;
		if (candle_1.priceClosed == 0) return false;

		return priceClosed > candle_1.priceClosed;
	}
	
	public boolean hasMoreVolumeThan(Candle candle) {
		return volume > candle.volume;
	}
	
	public boolean isWhite() {
		if (priceOpened == 0) return false;
		if (priceClosed > priceOpened) return true;
		else return false;
	}

	public boolean isBlack() {
		if (priceClosed < priceOpened) return true;
		else return false;
	}
	
	public boolean isDoji(Candle candleYtd) {
		if (priceHigh == 0) return false;
		if (priceLow == 0) return false;
		if (priceOpened == 0) return false;
		if (priceClosed == 0) return false;
		
		if (priceClosed == priceOpened && candleYtd.priceLow >= priceClosed) return true;
		else return false;
	}

	private boolean isDoji() {
		if (priceClosed == priceOpened) return true;
		else return false;
	}

	private boolean hasTail() {
		float bodyLow = Math.min(priceClosed, priceOpened);
		if (bodyLow > priceLow) return true;
		else return false;
	}

	public boolean hasBody() {
		if (priceOpened == 0) return false;
		if (priceClosed == 0) return false;
		
		if (priceOpened != priceClosed) return true;
		else return false;
	}

	private boolean isDash() {
		float price = priceClosed;
		if (price == priceOpened && price == priceLow && price == priceHigh) return true;
		else return false;
	}

	private int getTailLengthInTicks() {
		float bodyLow = Math.min(priceClosed, priceOpened);
		float diff = bodyLow - priceLow;
		double d = diff * 1000;
		d = Math.round(d);
		d = d/1000;
		double ticks = d / tickSize;
		return (int) ticks;
	}

	public int getValueRank() {
		return valueRank;
	}

	public void setValueRank(int valueRank) {
		this.valueRank = valueRank;
	}

	public int getVolumeRank() {
		return volumeRank;
	}

	public void setVolumeRank(int volumeRank) {
		this.volumeRank = volumeRank;
	}
}
